﻿namespace NKernel.Core
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;

    using log4net;

    using Provider;

    /// <summary>
    /// Central location for all kernel-related properties - intended for use by external processes
    /// to configure the kernel prior to its execution.
    /// </summary>
    public class KernelProperties
    {
        #region Fields

        private const string ComponentLocationsKey = "ComponentLocations";
        private const string DefaultProviderKey = "DefaultProvider";
        private const string OverrideDirectiveFileKey = "OverrideDirectiveFile";
        private const string PriorityListKey = "PriorityList";

        private static readonly ILog Logger = LogManager.GetLogger(typeof (KernelProperties));

        private static string[] cleanupMethods = new[] { "Cleanup" };
        private static string[] componentLocations = new []{"."};
        private static string[] initMethods = new []{"Init"};
        private static IKernelProvider kernelProvider;
        private static string overrideDirectiveFile = string.Empty;
        private static string[] priorityList = new [] {""};
        private static string[] startMethods = new[] { "Start" };
        private static string[] stopMethods = new[] { "Stop" };

        #endregion Fields

        #region Constructors

        private KernelProperties()
        {
            //do nothing
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// Gets or sets the cleanup methods.
        /// </summary>
        /// <value>The cleanup methods.</value>
        public static string[] CleanupMethods
        {
            get { return cleanupMethods; }
            set
            {
                cleanupMethods = value;
            }
        }

        /// <summary>
        /// Returns the array of locations where components could be found
        /// </summary>
        public static string[] ComponentLocations
        {
            get { return componentLocations; }
        }

        /// <summary>
        /// Gets or sets the init methods.
        /// </summary>
        /// <value>The init methods.</value>
        public static string[] InitMethods
        {
            get { return initMethods; }
            set
            {
                initMethods = value;
            }
        }

        /// <summary>
        /// Property to return an instance of the KernelProvider
        /// </summary>
        public static IKernelProvider KernelProvider
        {
            get { return kernelProvider; }
        }

        ///<summary>
        ///</summary>
        public static string OverrideDirectiveFile
        {
            get { return overrideDirectiveFile; }
        }

        /// <summary>
        /// Gets the priority list.
        /// </summary>
        /// <value>The priority list.</value>
        public static string[] PriorityList
        {
            get { return priorityList; }
        }

        /// <summary>
        /// Gets or sets the start methods.
        /// </summary>
        /// <value>The start methods.</value>
        public static string[] StartMethods
        {
            get { return startMethods; }
            set
            {
                startMethods = value;
            }
        }

        /// <summary>
        /// Gets or sets the stop methods.
        /// </summary>
        /// <value>The stop methods.</value>
        public static string[] StopMethods
        {
            get { return stopMethods; }
            set
            {
                stopMethods = value;
            }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Set the kernel properties through the use of a configuration file
        /// </summary>
        /// <param name="configuration"></param>
        public static void Configuration(IDictionary<string, string> configuration)
        {
            ComponentLocationsConfig(configuration[ComponentLocationsKey]);
            DefaultProviderConfig(configuration[DefaultProviderKey]);
            PriorityListConfig(configuration[PriorityListKey]);
            OverrideDirectiveFileConfig(configuration[OverrideDirectiveFileKey]);
        }

        private static void ComponentLocationsConfig(string value)
        {
            if (String.IsNullOrEmpty(value))
            {
                return;
            }

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug("Component locations value: " + value);
            }
            componentLocations = value.Split(new[] { ';' });
        }

        private static void DefaultProviderConfig(string value)
        {
            if (String.IsNullOrEmpty(value))
            {
                return;
            }

            object instance = Assembly.GetExecutingAssembly().CreateInstance(value);

            if (instance == null)
            {
                Logger.Error("Default kernel provider cannot be null!");
            }
            else
            {
                kernelProvider = instance as IKernelProvider;
            }
        }

        private static void OverrideDirectiveFileConfig(string value)
        {
            if (String.IsNullOrEmpty(value))
            {
                return;
            }

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug("Component override directive value: " + value);
            }
            overrideDirectiveFile = value;
        }

        private static void PriorityListConfig(string value)
        {
            if (String.IsNullOrEmpty(value))
            {
                return;
            }

            if (Logger.IsDebugEnabled)
            {
                Logger.Debug("Priority components: " + value);
            }
            priorityList = value.Split(new[] { ';' });
        }

        #endregion Methods
    }
}